﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security;
using System.Text;
using System.Threading.Tasks;

namespace SPWarmUp
{
    /// <summary>
    /// Implements a text log file.
    /// </summary>
    internal class TextFileLog : IDisposable
    {
        #region Fields
        /// <summary>The current directory.</summary>
        private string _filePath;
        private string _fileName;
        private string _fullPathAndFile;
        private FileStream _fileStream;
        private TextWriter _textWriter;
        private string _status;
        private bool _ready = false;
        #endregion

        #region Properties
        /// <summary>
        /// Gets the status of the text log file after construction.
        /// </summary>
        public string Status { get { return _status; } }

        /// <summary>
        /// Indicates whether or not this <see cref="TextFileLog"/> instance is ready for use.
        /// </summary>
        public bool IsReady { get { return _ready; } }

        /// <summary>
        /// Gets the full path and file name of the log file created as the log sink.
        /// </summary>
        public string FullPathAndFile { get { return _fullPathAndFile; } }
        #endregion

        #region Construction
        /// <summary>
        /// Constructs a new <see cref="TextLogFile"/> using a new file in the current directory.
        /// </summary>
        /// <remarks>Errors which may occur during creation of a new file are recorded in the <see cref="Status"/> property. The <see cref="IsReady"/>
        /// property is set to true if a new file was successfully created. Using a <see cref="TextFileLog"/> where <see cref="IsReady"/> is false
        /// will result in no logging.</remarks>
        public TextFileLog()
        {
            _fileName = DateTime.Now.ToString( "yyyy_MM_dd_HH_mm_ss" ) + ".log";
            try
            {
                _filePath = Directory.GetCurrentDirectory();
            }
            catch( NotSupportedException )
            {
                _status = "Cannot create log, not supported on Windows CE/.NET Compact Framework";
                return;
            }
            _fullPathAndFile = Path.Combine( _filePath, _fileName );
            try
            {
                _fileStream = File.Create( _fullPathAndFile, 4096, FileOptions.None );
                _textWriter = new StreamWriter( _fileStream, System.Text.Encoding.UTF8 );
                _status = "Log file ready";
                _ready = true;
            }
            catch( UnauthorizedAccessException )
            {
                _status = "Cannot create log, access denied";
            }
            catch( PathTooLongException )
            {
                _status = "Cannot create log, path too long";
            }
            catch( DirectoryNotFoundException )
            {
                _status = "Cannot create log, could not write to " + _filePath;
            }
            catch( IOException )
            {
                _status = "Cannot create log, I/O request failed";
            }
            catch( NotSupportedException )
            {
                _status = "Cannot create log, creating files not supported";
            }
        }
        #endregion

        #region Public API
        /// <summary>
        /// Deletes all existing log files.
        /// </summary>
        public static void Cleanup()
        {
            string directory;
            try
            {
                directory = Directory.GetCurrentDirectory();
            }
            catch( NotSupportedException )
            {
                return;
            }
            try
            {
                DirectoryInfo currentDirectory = new DirectoryInfo( directory );
                var logs = currentDirectory.GetFiles( "????_??_??_??_??_??.log" );
                if( logs != null )
                {
                    foreach( FileInfo file in logs )
                    {
                        try { file.Delete(); } catch { }
                    }
                }
            }
            catch( SecurityException )
            {
                // Fail silently, for now
            }
            catch( PathTooLongException )
            {
                // Fail silently, for now
            }
        }

        /// <summary>
        /// Writes text to the log file.
        /// </summary>
        /// <param name="text">Any text to write to the log file.</param>
        /// <remarks>Null or empty strings will not be written to the log file and are simply ignored without error.</remarks>
        public void Write( string text )
        {
            if( !_ready || String.IsNullOrEmpty( text ) )
            {
                return;
            }
            _textWriter.Write( text );
        }

        /// <summary>
        /// Writes text to the log file and moves the log file to the next line.
        /// </summary>
        /// <param name="text">Any text to write to the log file.</param>
        /// <remarks>Null or empty strings will not be written to the log file and are simply ignored without error.</remarks>
        public void WriteLine( string text )
        {
            if( !_ready || String.IsNullOrEmpty( text ) )
            {
                return;
            }
            _textWriter.WriteLine( text );
        }

        /// <summary>
        /// Closes and disposes the underlying steams writing to the file system.
        /// </summary>
        public void Dispose()
        {
            using( _textWriter )
            {
            }
            _textWriter = null;
            using( _fileStream )
            {
            }
            _fileStream = null;
            _ready = false;
        }
        #endregion
    }
}
